#include "GXHTC3.h"
#define POLYNOMIAL 0x31 // P(x) = x^8 + x^5 + x^4 + 1 = 00110001

// CRC校验
uint8_t gxhtc3_calc_crc(uint8_t *crcdata, uint8_t len)
{
  uint8_t crc = 0xFF;

  for (uint8_t i = 0; i < len; i++)
  {
    crc ^= (crcdata[i]);
    for (uint8_t j = 8; j > 0; --j)
    {
      if (crc & 0x80)
        crc = (crc << 1) ^ POLYNOMIAL;
      else
        crc = (crc << 1);
    }
  }
  return crc;
}
static uint8_t cmd_read_id[2] = {0xEF, 0xC8};
// 读取ID
ParseResult gxhtc3_read_id(void)
{
  return ldg_i2c_master_read(GXHTC3_ADDR, cmd_read_id, 2, 3);
}

static uint8_t cmd_wake_up[2] = {0x35, 0x17};
// 唤醒
ParseResult gxhtc3_wake_up(void)
{
  return ldg_i2c_master_write(GXHTC3_ADDR, cmd_wake_up, 2, 0);
}

static uint8_t cmd_measure[2] = {0x7C, 0xA2};
// 测量
ParseResult gxhtc3_measure(void)
{
  return ldg_i2c_master_write(GXHTC3_ADDR, cmd_measure, 2, 0);
}

uint8_t tah_data[6];
// 读出温湿度数据
ParseResult gxhtc3_read_tah(void)
{
  ParseResult result;
  result.status = ESP_FAIL;
  esp_err_t ret = ldg_i2c_master_init();
  if (ret != ESP_OK)
  {
    ESP_LOGE("I2C主机", "I2C主机初始化错误");
    return result;
  }

  ret = i2c_driver_install(0, I2C_MODE_MASTER, 0, 0, 0);
  if (ret != ESP_OK)
  {
    ESP_LOGE("I2C主机", "I2C驱动安装错误");
    return result;
  }

  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, 0x70 << 1 | I2C_MASTER_READ, true);
  i2c_master_read(cmd, tah_data, 6, I2C_MASTER_LAST_NACK);
  i2c_master_stop(cmd);

  ret = i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);

  i2c_cmd_link_delete(cmd);
  result.status = ret;
  result.data = tah_data;
  i2c_driver_delete(0);
  return result;
}

static uint8_t cmd_sleep[2] = {0xB0, 0x98};
// 休眠
ParseResult gxhtc3_sleep(void)
{
  return ldg_i2c_master_write(GXHTC3_ADDR, cmd_sleep, 2, 0);
}

uint16_t rawValueTemp, rawValueHumi;
float temp = 0, humi = 0;
uint8_t temp_int, humi_int;

// 获取并计算温湿度数据
esp_err_t gxhtc3_get_tah(void)
{
  int ret;

  gxhtc3_wake_up();
  gxhtc3_measure();
  vTaskDelay(20 / portTICK_PERIOD_MS);
  gxhtc3_read_tah();
  gxhtc3_sleep();

  if ((tah_data[2] != gxhtc3_calc_crc(tah_data, 2) || (tah_data[5] != gxhtc3_calc_crc(&tah_data[3], 2))))
  {
    temp = 0;
    humi = 0;
    temp_int = 0;
    humi_int = 0;
    ret = ESP_FAIL;
  }
  else
  {
    rawValueTemp = (tah_data[0] << 8) | tah_data[1];
    rawValueHumi = (tah_data[3] << 8) | tah_data[4];
    temp = (175.0 * (float)rawValueTemp) / 65535.0 - 45.0;
    humi = (100.0 * (float)rawValueHumi) / 65535.0;
    temp_int = round(temp);
    humi_int = round(humi);
    ret = ESP_OK;
  }
  return ret;
}